#include <libipc.h> // contient struct message, SIZEBUF et NUMBOITEREQ
#include <libthrd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <math.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <regex.h>
#include "gestion_admin.h"
#include "gestion_client.h" // contient NUMREP et extern struct tableUser
#include "workflow_struct.h"

void* ecoute_operation(void* arg) {		/* ajoute numero boite admin qui font listen dans la table */
	struct message* m = (struct message*) arg;
	P(VERROUTABLEBOITES);
	listBoite.numero = (int*) realloc(listBoite.numero, (listBoite.nb + 1)
			* sizeof(int));
	listBoite.numero[listBoite.nb] = m->boitereponse;
	listBoite.nb++;
	V(VERROUTABLEBOITES);
	free(m);
	return 0;
}
void* supprime_ecoute(void* arg) {		/* suppression de la boite admin de la table lors du SIGINT */
	struct message* m = (struct message*) arg;
	P(VERROUTABLEBOITES);
	int i = 0;
	while (m->boitereponse != listBoite.numero[i]) {
		i++;
	}
	listBoite.numero[i] = listBoite.numero[listBoite.nb - 1];
	listBoite.numero = (int*) realloc(listBoite.numero, (listBoite.nb - 1)
			* sizeof(int));
	listBoite.nb--;
	V(VERROUTABLEBOITES);
	free(m);
	return 0;
}
void* ecoute_clients() {		/* reception des message provenant de gestionclient et redistribution aux admins */
	struct message* m = malloc(sizeof(struct message));
	int i;
	int boitereponseAdmin;
	int boitereponseClient;
	boitereponseClient = creer_boite(NUMREP);	/* boite gestionclient-gestionadmin */
	while (1) {
#ifdef VERBOSE
		fprintf(stderr, "attente message ecoute\n");
#endif
		recevoir_message(boitereponseClient, m);
		P(VERROUTABLEBOITES);
		if (listBoite.nb != 0) {
			for (i = 0; i < listBoite.nb; i++) {
				boitereponseAdmin = listBoite.numero[i]; // num boitereponse du prog admin
				m->coupe = 1;
				envoyer_message(boitereponseAdmin, m);
			}
		}
		V(VERROUTABLEBOITES);
		bzero(m->buffer, SIZEBUF);
	}
	free(m);
	return 0;
}

int ajoutUser(char* identifiant) {
	int fd;
	char* ligne;
	if ((fd = open(fichierUsers, O_WRONLY | O_APPEND)) < 0) { /* ouverture fichier contenant les users */
#ifdef VERBOSE
		perror("open");
#endif
		exit(-1);
	}
	ligne = strtok(identifiant, "-");		/* reformatage de la chaine "-" deviendra " " dans le fichier */
	if (write(fd, ligne, strlen(ligne)) == -1) {
#ifdef VERBOSE
		perror("write1");
#endif
		exit(-1);
	}
	if (write(fd, " ", sizeof(char)) == -1) {
#ifdef VERBOSE
		perror("write1");
#endif
		exit(-1);
	}
	ligne = strtok(NULL, " ");
	if (write(fd, ligne, strlen(ligne)) == -1) {
#ifdef VERBOSE
		perror("write1");
#endif
		exit(-1);
	}
	if (write(fd, "\n", 1) == -1) {
#ifdef VERBOSE
		perror("write2");
#endif
		exit(-1);
	}
	close(fd);
	return (0);
}

char* recup_list() {
	char* list = NULL;
	int fd;
	if ((fd = open(fichierUsers, O_RDONLY)) < 0) {
		perror("open");
		exit(-1);
	}
	char *login;
	char *password;
	char *nom;
	char *prenom;
	int size = 0;
	while (findUser(&login, &password, &nom, &prenom, fd) == 0) {	/* recuperation de toute les info users puis reordonne login: nom prenom */
		list = (char*) realloc(list, (size + strlen(login) + strlen(nom)
				+ strlen(prenom) + 5) * sizeof(char));
		memcpy(list + size, login, strlen(login));
		memcpy(list + size + strlen(login), " : ", 3 * sizeof(char));
		memcpy(list + size + strlen(login) + 3, nom, strlen(nom));
		memcpy(list + size + strlen(login) + 3 + strlen(nom), " ", sizeof(char));
		memcpy(list + size + strlen(login) + 3 + strlen(nom) + 1, prenom,
				strlen(prenom));
		memcpy(list + size + strlen(login) + 3 + strlen(nom) + 1 + strlen(
				prenom), "\n", sizeof(char));
		size = size + strlen(login) + strlen(nom) + strlen(prenom) + 5;
		free(login);
		free(password);
		free(nom);
		free(prenom);
	}
	list = realloc(list, size + 1);
	list[size] = '\0';
	return list;
}
int userExist(char * login) {		/* fonction test si un login est deja utilise dans le fichier users */
	char * result;					/* renvoi 0 si non 1 si oui */
	char * ligne;
	int trouve = 0;
#ifdef VERBOSE
	fprintf(stderr, "login a tester: %s \n",login);
#endif
	int fd = open(fichierUsers, O_RDONLY);
	if (fd < 0) {
#ifdef VERBOSE
		fprintf(stderr, "fichier:%s\n", fichierUsers);
#endif
		perror("open");
		exit(-1);
	}
	while (trouve == 0) {
		ligne = lit_commande(fd);
		if (ligne == NULL) {
			return 0;
		}
		result = strtok(ligne, ":");
#ifdef VERBOSE
	fprintf(stderr, "result1: %s \n",result);
#endif
		if (strcmp(result,login) == 0) {
			trouve = 1;
		} else {
			trouve = 0;
		}
#ifdef VERBOSE
	fprintf(stderr, "trouve: %d \n",trouve);
#endif
	}
	free(ligne);
	close(fd);
	return trouve;
}

void* AddUser(void * arg) {			/* ajouter un users */
	struct message* m = (struct message*) arg;
	regex_t preg;			/* pour enregistrer un ER */
	int err;
	char buf_err[512];		/* pour connaitre cause si erreur regcomp */
	char *str_request=calloc(strlen(m->buffer),sizeof(char));
	strcpy(str_request,m->buffer);
#ifdef VERBOSE
	fprintf(stderr, "Argument à tester (%s) \n", str_request);
#endif
	const char *str_regex ="^[a-zA-Z0-9]+[:][a-zA-Z0-9]+[:][A-Za-z]+[-][A-Za-z]+$";	/* l'ER */
	err = regcomp(&preg, str_regex, REG_NOSUB | REG_EXTENDED); /* enregistrement de l'ER dans preg */
#ifdef VERBOSE
	fprintf(stderr, "Resultat regcomp %d\n", err);
#endif
	if (err == 0) {	/* err=0 => ER valide */
		int match;
		match = regexec(&preg,str_request, 0, NULL, 0); /* test si le format correspond à l'ER */
#ifdef VERBOSE
		fprintf(stderr, "Resultat match %d\n", match);
#endif
		regfree(&preg);
		if (match == 0) { /* format valide */
			char *login;
			login = strtok(str_request, ":");
			if (userExist(login) == 0) {   /* test si un user ne possede pas le meme login */
#ifdef VERBOSE
				fprintf(stderr, "Ajout d'un utilisateur %s\n", m->buffer);
#endif
				int ajout = ajoutUser(m->buffer);
				bzero(m->buffer, SIZEBUF);
				if (ajout == 0) {
					char* buf = "Succesful add user\0";
#ifdef VERBOSE
					fprintf(stderr, "Ajout reussi\n");
#endif
					strcpy(m->buffer, buf);
				}
				if (ajout != 0) {
					char* buf = "Error add user\0";
#ifdef VERBOSE
					fprintf(stderr, "Ajout loupe\n");
#endif
					strcpy(m->buffer, buf);
				}
			} else {
				bzero(m->buffer, SIZEBUF);
				char* buf = "Login deja attribue \0";
#ifdef VERBOSE
				fprintf(stderr, "Login deja utilise \n");
#endif
				strcpy(m->buffer, buf);
			}
		} else {
			bzero(m->buffer, SIZEBUF);
			char* buf = "Mauvais format attendu : \"pseudo:mdp:prenom-nom\" \0";
#ifdef VERBOSE
			fprintf(stderr, "Mauvais format\n");
#endif
			strcpy(m->buffer, buf);
		}
	} else {
		regerror(err, &preg, buf_err, sizeof(buf_err)); /* recupere cause erreur regcomp dans buf_err */
#ifdef VERBOSE
		fprintf(stderr, "Regcomp erreur: %s\n", buf_err);
#endif
		exit(-1);
	}
	envoyer_message(m->boitereponse, m);
#ifdef VERBOSE
	fprintf(stderr, "Message reponse envoye\n");
#endif
	free(m);
	return 0;
}

void* operation(void* arg) {	/* appel les differentes fonction pour -c et -u */
	struct message* m = (struct message*) arg;
	bzero(m->buffer, SIZEBUF);
	int i;
	char* buf = NULL;
	if (m->code == 1) { /* liste utilisateur dans users */
#ifdef VERBOSE
		fprintf(stderr, "recup list\n");
#endif
		buf = recup_list();
#ifdef VERBOSE
		fprintf(stderr, "recup list result :%s\n", buf);
#endif
	}
	if (m->code == 2) { /* liste utilisateur connecté */
#ifdef VERBOSE
		fprintf(stderr, "recup connect\n");
#endif
		buf = recup_connect();
#ifdef VERBOSE
		fprintf(stderr, "recup connect result :%s\n", buf);
#endif
	}
#ifdef VERBOSE
	fprintf(stderr, "size buf :%d\n", strlen(buf));
#endif
	if (strlen(buf) > 0) {
		int coupe = ceil(strlen(buf) / SIZEBUF); /* decoupe si buf trop long poru envoyé plusieurs packets */
		for (i = 0; i <= coupe; i++) {
			strncpy(m->buffer, buf + (i * SIZEBUF), SIZEBUF);
			m->numpacket = i + 1;
			m->coupe = 1;
			if (coupe == i) {
				m->coupe = 0;
			}
			envoyer_message(m->boitereponse, m);
		}
	} else { /* par logique n'est possible que pour -c */
		strcpy(m->buffer, "Aucune personne connectee\n");
		m->coupe = 0;
		envoyer_message(m->boitereponse, m);
	}
	free(buf);
	free(m);
	return 0;
}

void* gestionAdmin(void* param) {
	struct message* mrequete = malloc(sizeof(struct message));
	traitement(NULL, ecoute_clients);	/* tourne en boucle sur un autre thread */
	int boiterequete = creer_boite(NUMBOITEREQ); /* boiterequete venant du main admin */
#ifdef VERBOSE
	fprintf(stderr, "boiterequete cree\n");
#endif
	recevoir_message(boiterequete, mrequete);
	while (1) {
#ifdef VERBOSE
		fprintf(stderr, "traitement cmd admin\n");
		fprintf(stderr, "code : %ld\n", mrequete->code);
#endif
		if (mrequete->code == 1 || mrequete->code == 2) { /* -u et -c */
			traitement(mrequete, operation);
		}
		if (mrequete->code == 3) {				/* -a */
			traitement(mrequete, AddUser);
		}
		if (mrequete->code == 4) {				/* -l */
			traitement(mrequete, ecoute_operation);
		}
		if (mrequete->code == 5) {				/* SIGINT */
			traitement(mrequete, supprime_ecoute);
		}
		//nouvelle allocation car sinon on aura un probleme avec plusieurs admins sur le serveur qui vont partager un seul segment memoire
		//le free se fait dans chaque thread charge de gerer les differents messages
		mrequete = malloc(sizeof(struct message));
		recevoir_message(boiterequete, mrequete);
	}
}
